using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using RenameX.Models;

namespace RenameX.Services
{
    public class RenameOperation
    {
        public string FromPath { get; set; } = string.Empty;
        public string ToPath { get; set; } = string.Empty;
    }

    public class RenameService
    {
        private readonly Stack<List<RenameOperation>> _history = new();

        public Task<bool> PrecheckAsync(IEnumerable<FileItem> files)
        {
            return Task.Run(() =>
            {
                var targets = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
                foreach (var f in files)
                {
                    var dir = Path.GetDirectoryName(f.OriginalPath) ?? string.Empty;
                    var ext = string.IsNullOrEmpty(f.NewExtension) ? Path.GetExtension(f.OriginalPath) : "." + f.NewExtension;
                    var dest = Path.Combine(dir, f.NewName + ext);
                    if (targets.Contains(dest)) return false;
                    if (File.Exists(dest) && !string.Equals(dest, f.OriginalPath, StringComparison.OrdinalIgnoreCase)) return false;
                    targets.Add(dest);
                }
                return true;
            });
        }

        public async Task<bool> ExecuteAsync(IList<FileItem> files)
        {
            if (!await PrecheckAsync(files)) return false;

            var ops = new List<RenameOperation>();
            try
            {
                foreach (var f in files)
                {
                    var dir = Path.GetDirectoryName(f.OriginalPath) ?? string.Empty;
                    var ext = string.IsNullOrEmpty(f.NewExtension) ? Path.GetExtension(f.OriginalPath) : "." + f.NewExtension;
                    var dest = Path.Combine(dir, f.NewName + ext);

                    if (string.Equals(dest, f.OriginalPath, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    Directory.CreateDirectory(dir);
                    File.Move(f.OriginalPath, dest);
                    ops.Add(new RenameOperation { FromPath = f.OriginalPath, ToPath = dest });
                    f.OriginalPath = dest;
                    f.OriginalName = Path.GetFileNameWithoutExtension(dest);
                }

                if (ops.Count > 0)
                {
                    _history.Push(ops);
                }
                return true;
            }
            catch
            {
                // best-effort rollback of current batch
                foreach (var op in Enumerable.Reverse(ops))
                {
                    try
                    {
                        if (File.Exists(op.ToPath))
                        {
                            File.Move(op.ToPath, op.FromPath);
                        }
                    }
                    catch
                    {
                        // ignore
                    }
                }
                return false;
            }
        }

        public Task<bool> UndoAsync()
        {
            return Task.Run(() =>
            {
                if (_history.Count == 0) return false;
                var ops = _history.Pop();
                var any = false;
                foreach (var op in Enumerable.Reverse(ops))
                {
                    try
                    {
                        if (File.Exists(op.ToPath))
                        {
                            File.Move(op.ToPath, op.FromPath);
                            any = true;
                        }
                    }
                    catch
                    {
                        // ignore and continue
                    }
                }
                return any;
            });
        }
    }
}


